1use crate::re::NiColor::NiColor;
2use core::fmt;
3use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
4
5#[repr(C)]
9#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
10pub struct Color {
11 pub red: u8,
12 pub green: u8,
13 pub blue: u8,
14 pub alpha: u8,
15}
16const _: () = assert!(core::mem::size_of::<Color>() == 0x4);
17
18impl Color {
19 #[inline]
21 pub const fn new(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
22 Self { red, green, blue, alpha }
23 }
24
25 #[inline]
27 pub const fn from_hex(hex: u32) -> Self {
28 Self {
29 red: ((hex >> 16) & 0xFF) as u8,
30 green: ((hex >> 8) & 0xFF) as u8,
31 blue: (hex & 0xFF) as u8,
32 alpha: 0,
33 }
34 }
35
36 #[inline]
38 pub const fn to_u32(&self) -> u32 {
39 ((self.red as u32) << 24)
40 | ((self.green as u32) << 16)
41 | ((self.blue as u32) << 8)
42 | (self.alpha as u32)
43 }
44
45 pub fn to_hex_string(&self) -> String {
47 format!("#{:02X}{:02X}{:02X}{:02X}", self.red, self.green, self.blue, self.alpha)
48 }
49
50 #[inline]
52 pub const fn as_slice(&self) -> [u8; 4] {
53 [self.red, self.green, self.blue, self.alpha]
54 }
55}
56
57impl fmt::Display for Color {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(f, "#{:02X}{:02X}{:02X}{:02X}", self.red, self.green, self.blue, self.alpha)
61 }
62}
63
64impl Add for Color {
67 type Output = Self;
68
69 #[inline]
70 fn add(self, rhs: Self) -> Self::Output {
71 Self {
72 red: self.red.saturating_add(rhs.red),
73 green: self.green.saturating_add(rhs.green),
74 blue: self.blue.saturating_add(rhs.blue),
75 alpha: self.alpha.saturating_add(rhs.alpha),
76 }
77 }
78}
79
80impl AddAssign for Color {
81 #[inline]
82 fn add_assign(&mut self, rhs: Self) {
83 self.red = self.red.saturating_add(rhs.red);
84 self.green = self.green.saturating_add(rhs.green);
85 self.blue = self.blue.saturating_add(rhs.blue);
86 self.alpha = self.alpha.saturating_add(rhs.alpha);
87 }
88}
89
90impl Sub for Color {
91 type Output = Self;
92
93 #[inline]
94 fn sub(self, rhs: Self) -> Self::Output {
95 Self {
96 red: self.red.saturating_sub(rhs.red),
97 green: self.green.saturating_sub(rhs.green),
98 blue: self.blue.saturating_sub(rhs.blue),
99 alpha: self.alpha.saturating_sub(rhs.alpha),
100 }
101 }
102}
103
104impl SubAssign for Color {
105 #[inline]
106 fn sub_assign(&mut self, rhs: Self) {
107 self.red = self.red.saturating_sub(rhs.red);
108 self.green = self.green.saturating_sub(rhs.green);
109 self.blue = self.blue.saturating_sub(rhs.blue);
110 self.alpha = self.alpha.saturating_sub(rhs.alpha);
111 }
112}
113
114impl Mul for Color {
115 type Output = Self;
116
117 #[inline]
118 fn mul(self, rhs: Self) -> Self::Output {
119 Self {
120 red: self.red.saturating_mul(rhs.red),
121 green: self.green.saturating_mul(rhs.green),
122 blue: self.blue.saturating_mul(rhs.blue),
123 alpha: self.alpha.saturating_mul(rhs.alpha),
124 }
125 }
126}
127
128impl MulAssign for Color {
129 #[inline]
130 fn mul_assign(&mut self, rhs: Self) {
131 self.red = self.red.saturating_mul(rhs.red);
132 self.green = self.green.saturating_mul(rhs.green);
133 self.blue = self.blue.saturating_mul(rhs.blue);
134 self.alpha = self.alpha.saturating_mul(rhs.alpha);
135 }
136}
137
138impl Div for Color {
139 type Output = Self;
140
141 #[inline]
142 fn div(self, rhs: Self) -> Self::Output {
143 Self {
144 red: self.red.saturating_div(rhs.red.max(1)), green: self.green.saturating_div(rhs.green.max(1)),
146 blue: self.blue.saturating_div(rhs.blue.max(1)),
147 alpha: self.alpha.saturating_div(rhs.alpha.max(1)),
148 }
149 }
150}
151
152impl DivAssign for Color {
153 #[inline]
154 fn div_assign(&mut self, rhs: Self) {
155 self.red = self.red.saturating_div(rhs.red.max(1));
156 self.green = self.green.saturating_div(rhs.green.max(1));
157 self.blue = self.blue.saturating_div(rhs.blue.max(1));
158 self.alpha = self.alpha.saturating_div(rhs.alpha.max(1));
159 }
160}
161
162impl Mul<u8> for Color {
165 type Output = Self;
166
167 #[inline]
168 fn mul(self, scalar: u8) -> Self::Output {
169 Self {
170 red: self.red.saturating_mul(scalar),
171 green: self.green.saturating_mul(scalar),
172 blue: self.blue.saturating_mul(scalar),
173 alpha: self.alpha.saturating_mul(scalar),
174 }
175 }
176}
177
178impl Div<u8> for Color {
179 type Output = Self;
180
181 #[inline]
182 fn div(self, scalar: u8) -> Self::Output {
183 Self {
184 red: self.red.saturating_div(scalar.max(1)),
185 green: self.green.saturating_div(scalar.max(1)),
186 blue: self.blue.saturating_div(scalar.max(1)),
187 alpha: self.alpha.saturating_div(scalar.max(1)),
188 }
189 }
190}
191
192impl From<NiColor> for Color {
193 #[inline]
194 fn from(value: NiColor) -> Self {
195 Self { red: value.red as u8, green: value.green as u8, blue: value.blue as u8, alpha: 0 }
196 }
197}
198
199#[test]
200fn test_color_operations() {
201 let color1 = Color::new(100, 150, 200, 255);
202 let color2 = Color::new(50, 50, 50, 128);
203
204 assert_eq!(color1 + color2, Color::new(150, 200, 250, 255));
205 assert_eq!(color1 - color2, Color::new(50, 100, 150, 127));
206 assert_eq!(color1 * color2, Color::new(255, 255, 255, 255));
207 assert_eq!(color1 / color2, Color::new(2, 3, 4, 1));
208
209 assert_eq!(color1 * 2, Color::new(200, 255, 255, 255));
211 assert_eq!(color1 / 2, Color::new(50, 75, 100, 127));
212}